/*
 *  bytecodes.h
 *  joosVM
 *
 *  Created by Smári Waage on 15.6.2009.
 *  Copyright 2009 smari.org. All rights reserved.
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. *
 */

#ifndef bytecodes___ 
#define bytecodes___ 

#include "objects.h"


#if TRACE_JIT

inline static void restore(JoosSideExit* ex, Stack* s, mem_slot* a, bool record){
	
	TraceRecorder* rec;
	if(record){
		//start a new trace recorder to record the extension.
		rec = new TraceRecorder(s->fp()->getMethod(),ex);
		dout(debug_trace,"Starting an extension recording:%p\n",rec->fragment);
	}
	
	int levelcount = ex->levelpos +1;
	JoosSideExit* restoreLevels[levelcount];
	JoosSideExit* restoreExit = ex;
	//revers the list and putit in an array.
	for(int i=levelcount-1;i>=0;i--){
		//JASSERT(ex && ex->exitType == WrongBranch)
		restoreLevels[i] = restoreExit;
		restoreExit = restoreExit->next;
		JASSERT((!i==0)|| restoreExit == NULL) //make sure we got all.
	}
	
	
	//get the right trace tree object
	TraceTreeObject* ttree = (TraceTreeObject*)ex->from->root->vmprivate;
	//level 0 doesn't have to push a frame on, only has to be the same.
	JASSERT(ttree->getVTable()->get(restoreLevels[0]->method) == s->fp()->getMethod())
	
	
	if(restoreLevels[0]->stackPos>0){
		//sticky access, the location is at the end of the exit.
		mem_slot* stack = restoreLevels[0]->stack;// (mem_slot*)(restoreLevels[0]+sizeof(JoosSideExit));
		for(int i=0; i< restoreLevels[0]->stackPos;i++){
			s->pushPrim((Pointer*)stack[i]);
			//ddout("restore stack pos: %p\n",stack);
			rec->push(rec->lir->insLoad(LIR_ld, rec->lir->insImmPtr(stack), mem_slotIndex(i)) );
		}
		dout(debug_trace,"\tRebuilt stack:%i\n",restoreLevels[0]->stackPos)
	}
	
	for(int i=0; i<restoreLevels[0]->storeSize;i++){
		mem_slot v = a[restoreLevels[0]->storeStartIdx+i];
		s->fp()->getLocals()->update(i, (Pointer*)v);
	}
	s->fp()->setPC(restoreLevels[0]->pc);
	dout(debug_trace,"\tLevel:0 PC:%i stackPos:%i in %s\n",restoreLevels[0]->pc, restoreLevels[0]->stackPos,s->fp()->getMethod()->getName()->str());
	
	
	
	
	for(int y=1;y<levelcount;y++){
		JMethod* method = (JMethod*)ttree->getVTable()->get(restoreLevels[y]->method);
		
		//load the locals
		int maxlocals = method->getMaxLocals();
		TaggedArray* locals = TaggedArray::Initalize(maxlocals);
		
		for(int i=0;i<restoreLevels[y]->storeSize;i++){ 
			//todo:carry type info... boo
			mem_slot v = a[restoreLevels[y]->storeStartIdx+i];
			locals->setPrim(i, (Pointer*)v);
			//ddout("val %i\n",v);
		}
		
		s->pushOnFrame(method, locals);
		if(record){
			rec->restoreLevel(method, restoreLevels[y-1]);
		}
		
		s->fp()->setPC(restoreLevels[y]->pc);
		
		if(restoreLevels[y]->stackPos>0){
			mem_slot* stack = (mem_slot*)(restoreLevels[y]+sizeof(JoosSideExit));
			for(int i=0; i< restoreLevels[y]->stackPos;i++){
				s->pushPrim((Pointer*)stack[i]);
				rec->push(rec->lir->insLoad(LIR_ld, rec->lir->insImmPtr(stack), mem_slotIndex(i)) );
			}
			dout(debug_trace,"\tRebuilt stack:%i\n",restoreLevels[y]->stackPos)
		}
		
		dout(debug_trace,"\tLevel:%i PC:%i stackPos:%i in %s\n",y,restoreLevels[y]->pc, restoreLevels[y]->stackPos, s->fp()->getMethod()->getName()->str());
	}

	
	if(record){
		rec->startRecord();
	}
}


inline static void makeCall(TraceTreeObject* ttree, Stack* s){
	

	Fragment* f = ttree->getFragment();

	code2Func u;
	u.code = f->code();
	
	GuardRecord* guard;
	JMethod* m = s->fp()->getMethod();
	int size = m->getMaxLocals();
	
	//create a memblock that can hold all the store.
	mem_slot b[ttree->getCallSize()];
	mem_slot *a = b;
	
	//load the locals.
	for(int i=0;i<size;i++){
		mem_slot v = (mem_slot)s->fp()->getLocals()->get(i);
		a[i] = v;
	}
	
	dout(debug_trace,"Make call to %p\n",f)
	
	//make the call to the trace
	Vtable* vt = (Vtable*)ttree->getVTable()->address()+StaticArray::kArrayOffset;
	guard = u.func(a,vt);
	
	JoosSideExit* ex = (JoosSideExit*)guard->exit;
	dout(debug_trace_short, "Exit Type:%i\n",ex->exitType);
	

	
	
	
	if(ex->exitType == NestedExit){
		//if we exit through a nested exit then we need to rebuild the untill we come to the place the nesting was done.
		bool delStore = false;
		
		if(Flags::recordTrace){
			//drop everything an try to extend the bad exit.
			dout(debug_trace, "Cancel recording, nested exit\n");
			TraceRecorder::current->cancelRecord();
			delete TraceRecorder::current;
		}
		//here a rebuild of the stackframes is needed.
		dout(debug_trace, "Exit on: %p\nexit type:NestedExit \nRestore levels:%i\n",ex,ex->levelpos+1);
		
		//identical to WrongBranch just dont start the recorder.
		int nestcount = 0;
		do{ //can be more than one nesting
			
			restore(ex, s, a,false);
			dout(debug_trace,"Done Nested restore\n")
			JASSERT(ex->nest && (ex->nest->exitType == WrongBranch || ex->nest->exitType == NestedExit))
			
			
			//TODO: remove, make space inside the nesting trace to hold the memblock.
			if(delStore)
				delete a;
			
			JASSERT(ex->nestStore)
			a = ex->nestStore;
			delStore = true;
			ex = ex->nest;
			JASSERT(nestcount++ <= 10)
			
		}while(ex->exitType == NestedExit);
		
		
	}
	
	
	if(ex->exitType == WrongBranch){
		
		//here a rebuild of the stackframes is needed.
		dout(debug_trace, "Exit on: %p\nexit type:WrongBranch \nRestore levels:%i\n",ex,ex->levelpos+1);
		
		//if we hit a wrong branch we drop everything we are doing and try to extend the loop.
		if(Flags::recordTrace){
			dout(debug_trace, "Cancel recording, wrong branch\n");
			//we are in the process of inlining the call, lets stop that and fix the loop.
			TraceRecorder::current->cancelRecord();
			delete TraceRecorder::current;
		}
				
		restore(ex, s, a, true);		
		dout(debug_trace,"Done restore\n")

	}else if(ex->exitType == LoopExit){
		
		for(int i=0;i<size;i++){
			mem_slot v = a[i];
			s->fp()->getLocals()->update(i, (Pointer*)v);
			//ddout("val %i\n",a[i]);
		}
		s->fp()->setPC(ex->pc);
		
		dout(debug_trace, "Exit on: %p\nexit type:LoopExit \nStack count: %i\nStore count: %i\nPC: %i\n",ex,ex->exitType,ex->stackPos,ex->storeSize,ex->pc);
		JASSERT(ex->stackPos==0)
		
	}else{
		
		ddout("Unhandled exit from fragment type: %i",ex->exitType);
		exit(1);
	}
	//delete a;
}

inline void checkNextLoopheader(Stack* s){
	
	//TODO: something else than check in every bytecode for loop header.
	bool b = s->fp()->getMethod()->checkLoopHead(s->fp()->getPC());
	if(b){
		//There is something here.
		TraceTreeObject* trec = (TraceTreeObject*)s->fp()->getMethod()->backJump(s->fp()->getPC());
		//JASSERT(TraceRecorder::current != trec)
		
		if((int)trec > 1 && trec->getState() == Compiled){
			//we found a loopheader that has a tree that is compiled. 
			dout(debug_trace, "\tFound a compiled tree in %s\n",s->fp()->getMethod()->getName()->str())
			
			//inline the tree by calling it.
			TraceRecorder::current->makeTreeCall(trec->getFragment());
			
			//then we have to call the tree to move us past the tree.
			makeCall(trec, s);
			//call makes sure that the result is ok, else it cancels and stuff.
		}
		//if not we just catch it in the backloop.
	}
}


#endif

inline static void makeJump(signed short index, Stack* s){
	
	//The jump instruction is 3 byte long, by now the pc is in position to read the next instruction.
	int npc = (s->fp()->getPC() - 3) + index;	
	
#if TRACE_JIT
	//check if it is a back branch, then check the header if it had many hits.
	if(index < 0){
		if(TraceTreeObject* trec = (TraceTreeObject*)s->fp()->getMethod()->backJump(npc)){
			TraceRecorder* rec = TraceRecorder::current;
			
			if((int)trec == 1){//potential trace
				if(Flags::recordTrace){
					rec->cancelRecord();
				}
				//lassert(!Flags::recordTrace,"Loop became hot while in a outer-record")
				
				JMethod* m = s->fp()->getMethod();
				//Update Here..
				
				//create fragment
				TraceTreeObject* ttree = TraceTreeObject::Initialize();
				rec = new TraceRecorder(m,npc,s->fp()->getPC(),ttree);
				
				m->setFragmentRecorder(ttree,npc);
				rec->startRecord();
				
				dout(debug_trace,"Starting a new root fragment:%p in %s\n", rec->fragment,m->getName()->str());
				
			}else{
				
				if(Flags::recordTrace){
					
					if(trec->getFragment() == rec->fragment->root){
						dout(debug_trace, "Completing a new branch: %p in %s \n",
							 rec->fragment,s->fp()->getMethod()->getName()->str());
						//We are closing the fragment.
						rec->closeRecord();
						delete rec;
						
					} else {
						//we are recording and hit a tree that is not the same as the recording one.
						//this is bad because we have make a trip through the body of the soon-to-be 
						//nested loop and recorded guards and stuff.
						rec->cancelRecord();
						delete rec;
						//if(trec->getState() == Compiled){
							//this is realy bad because we should have figured out the loophead before we
							//entered the body.
						//	dout(debug_trace, "\tFound a compiled tree in a back loop %s\n",
						//		 s->fp()->getMethod()->getName()->str())
							
							//abort();
						//}					
					}
				}//end recording is on.
				
				//the pc is set to the right position in make call
				//have to return here becuse of rebuild of opStacks.
				if(trec->getState() == Compiled && trec->getFragment()->code() != NULL){
					makeCall(trec, s);
					return;
					
				}else if(trec->getState() == Canceled){
					
					//the recorder at this site is in canceled state
					JMethod* m = s->fp()->getMethod();
					
					rec = new TraceRecorder(m,npc,s->fp()->getPC(),trec);
					rec->startRecord();
					dout(debug_trace,"Restarting a trace;%p in %s\n",rec->fragment,m->getName()->str())
				}
			}
			
			
		}else{
			TRACE_REC(
					  //if we hit here then we hit a cold loop within the trace, the easiest thing todo is to cancel the current record start a new one to record the cold loop, and hope it will be inlined later. 
					  rec->cancelRecord();
					  delete rec;
					  dout(debug_trace,"Hit a cold loop\n ")
					  
					  //start a new record from here.
					  JMethod* m = s->fp()->getMethod();
					  TraceTreeObject* ttree = TraceTreeObject::Initialize();
					  rec = new TraceRecorder(m,npc,s->fp()->getPC(),ttree);
					  // rec->currentContext = &ct;
					  
					  dout(debug_trace,"Starting a new root fragment:%p in %s\n",rec->fragment,m->getName()->str());
					  m->setFragmentRecorder(ttree,npc);
					  rec->startRecord();
					  
					  )
			//I need to cancel the current record, start a record for this loop, then just hope we inline it later
		}
	}
	
#endif
	
	//I like to be on the safe side.
	if(npc >=0 && npc < s->fp()->getCode()->array_length()){
		s->fp()->setPC(npc);
	}else{
		printf("invalid branch jump index:%i\n",npc);exit(1);
	}
	dout(debug_bytecodes,"jump: new idx:%i length:%i\n",npc,s->fp()->getCode()->array_length());
}


class Bytecodes {

public:
	
#define T(identifier, debug, bytecode, size, off_count, on_count, type, method) identifier,
	enum Bytecode {
		BYTECODE_LIST(T)
		NUM_BYTECODES
	};
#undef T
	
	
	
	//Todo: move the implementation back up here, for inlining purposes
	
	static char* _bytecode_strs[];
	static char* LookupBytecode(byte code);
	
	
	
	

	/*
	 ######### End Help methods
	 */
#if TRACE_JIT
	DECLARE_CALLINFO(boxString);
	DECLARE_CALLINFO(aaload_f);
	DECLARE_CALLINFO(baload_f);
	DECLARE_CALLINFO(aastore_f);
	DECLARE_CALLINFO(getstatic_f);
	DECLARE_CALLINFO(putstatic_f);
	DECLARE_CALLINFO(arraylength_f);
#endif
	/*
	 ########## Bytecodes
	 */
	
	static void nop(Stack* s){;}
	static void aconst_null(Stack* s){ s->pushRef((Pointer*)1);} //Todo: change
	
	
	static void iconst_x(int i, Stack* s){
		s->pushPrim((Integer*)i);
		dout(debug_bytecodes, "iconst %i, ",i)
		TRACE_REC(
				  LIns* one = rec->lir->insImm(i); 
				  rec->push(one);
				  )
	}
	
	static void iconst_m1(Stack* s){iconst_x(-1,s);}
	static void iconst_0(Stack* s){iconst_x(0,s);}
	static void iconst_1(Stack* s){iconst_x(1,s);}
	static void iconst_2(Stack* s){iconst_x(2,s);}
	static void iconst_3(Stack* s){iconst_x(3,s);}
	static void iconst_4(Stack* s){iconst_x(4,s);}
	static void iconst_5(Stack* s){iconst_x(5,s);}
	
	static void lconst_0(Stack* s){
		s->pushLong(0);
		dout(debug_bytecodes,"lconst_0:, ",0)
		TRACE_REC(rec->push(rec->lir->insImmq(0));)
	}
	static void lconst_1(Stack* s){
		s->pushLong(1);
		dout(debug_bytecodes,"lconst_1:, ",0)
		TRACE_REC(rec->push(rec->lir->insImmq(1));)
	}
	
	//TODO: check casts....in trace recoreder..
	static void fconst_0(Stack* s){
		float f = 0.0;
		s->pushPrim(*(Pointer**)&f);
		dout(debug_bytecodes,"fconst_0, ",0)
		TRACE_REC(rec->push(rec->lir->insImmf(0.0));)
	}
	static void fconst_1(Stack* s){
		float f = 1.0;
		s->pushPrim(*(Pointer**)&f);
		dout(debug_bytecodes,"fconst_1, ",0)
		TRACE_REC(rec->push(rec->lir->insImmf(1.0));)
	}
	static void fconst_2(Stack* s){
		float f = 2.0;
		s->pushPrim(*(Pointer**)&f);
		dout(debug_bytecodes,"fconst_2, ",0)
		TRACE_REC(rec->push(rec->lir->insImmf(2.0));)
	}
	
	static void dconst_0(Stack* s){
		s->pushDbl(0.0);
		dout(debug_bytecodes,"dconst_0, ",0)
		TRACE_REC(rec->push(rec->lir->insImmf(0.0));)
	}
	
	static void dconst_1(Stack* s){
		s->pushDbl(1.0);
		dout(debug_bytecodes,"dconst_1, ",0)
		TRACE_REC(rec->push(rec->lir->insImmf(1.0));)
	}
	
	
	//16
	static void bipush(Stack* s){
		signed char value = s->getnextbyte();
		int i = value;
		s->pushPrim((Integer*)i);
		dout(debug_bytecodes,"bipush %i, ",i)
		TRACE_REC(rec->push(rec->lir->insImm(i));)
	};
	//17
	static void sipush(Stack* s){
		signed short value = s->getnextU4();
		int i = value;
		//automatic sign extension
		s->pushPrim((Integer*)i);
		dout(debug_bytecodes,"sipush %i, ",i)
		TRACE_REC(rec->push(rec->lir->insImm(i));)
	}
	
	
	inline static Instance* boxString(Pointer* cstring){
		JType* tString = ClassLoader::findType(String::charToString("java/lang/String"));
		JField* fd = tString->getField(String::charToString("c_str"));
		
		Instance* bla = Instance::Initialize(tString);
		bla->getValues()->set(fd->getName(),TaggedValue::Initalize(cstring, true));
		return bla;
	}
	
	
	
	
	
	inline static void xldc(int idx, Stack* s){
		StaticArray* cp = s->fp()->getType()->getConstantPool();
		Pointer* val = cp->get(idx-1);
		if(val->isSmi()){
			int a = ((Smi*)val)->value();
			Pointer* p = cp->get(a-1);
			s->pushRef(boxString(p));
			TRACE_REC(  
			LIns* args[] = {rec->insertPointer((HeapObject*)p)};
			LIns* re = rec->lir->insCall(&boxString_ci, args);
			rec->push(re);  
			)//String pointer... p is a c-string, some boxing is done here!!
			
		}else{
			Pointer* p = (Pointer*)((HeapPrimitive*)val)->getValue();  
			s->pushPrim(p);
			//constant value.
			TRACE_REC( rec->push(rec->lir->insImm((int32_t)p));)
		}
		dout(debug_bytecodes,"ldc: %p, ",val);
		
	}
	
	//18 -ath med type
	static void ldc(Stack* s){
		byte idx = s->getnextbyte();
		xldc(idx,s);
	}
	static void ldc_w(Stack* s){
		int idx = s->getnextU4();
		xldc(idx,s);
	}
	static void ldc2_w(Stack* s){
		int idx = s->getnextU4();
		StaticArray* cp = s->fp()->getType()->getConstantPool();
		HeapDblPrimitive* val = (HeapDblPrimitive*)cp->get(idx-1);
		u8 d = val->getValue();
		s->pushPrim((Pointer*)(d>>32));
		s->pushPrim((Pointer*)d);
		dout(debug_bytecodes,"ldc: %f\n",d);
		TRACE_REC( rec->push(rec->lir->insImmq(d));)
	}
	
	//26-29
	inline static void iload_x(int i, Stack* s){
		Pointer* value = s->fp()->getLocals()->get(i);
		s->pushPrim(value);
		dout(debug_bytecodes, "xload_%i: %p, ",i, s->peek())
		TRACE_REC(
				  rec->push(rec->getStoreSlot(i));
				  )
	}
	//21
	static void iload(Stack* s){
		byte idx = s->getnextbyte();
		iload_x(idx,s);
	}
	static void iload_0(Stack* s){ iload_x(0,s);}
	static void iload_1(Stack* s){ iload_x(1,s);}
	static void iload_2(Stack* s){ iload_x(2,s);}
	static void iload_3(Stack* s){ iload_x(3,s);}
	
	static void fload(Stack* s){
		byte idx = s->getnextbyte();
		iload_x(idx,s);
		TRACE_REC(BLACKLIST_TRACE) //All floting point operations in nanojit are 64bit(JS).
	}
	static void fload_0(Stack* s){ iload_x(0,s);TRACE_REC(BLACKLIST_TRACE)}
	static void fload_1(Stack* s){ iload_x(1,s);TRACE_REC(BLACKLIST_TRACE)}
	static void fload_2(Stack* s){ iload_x(2,s);TRACE_REC(BLACKLIST_TRACE)}
	static void fload_3(Stack* s){ iload_x(3,s);TRACE_REC(BLACKLIST_TRACE)}
	
	//42-45
	static void dload_x(int i, Stack* s){
		Pointer* high = s->fp()->getLocals()->get(i);
		Pointer* low = s->fp()->getLocals()->get(i+1);
		s->pushPrim(high);//high bits
		s->pushPrim(low);//low bits
		dout(debug_bytecodes, "xload_%i: %p, ",i,s->peek())
		
		TRACE_REC(
				  BLACKLIST_TRACE
				  /*
		 storeInfo* inf = rec->store(i);
		 if(!inf->current){
		 inf->current = rec->lir->insLoad(LIR_ldq,rec->fragment->lirbuf->state,i*sizeof(int32_t));
		 }
		 rec->push(inf->current);*/
				  )
	}
	
	static void lload(Stack* s){
		int idx = s->getnextbyte();
		dload_x(idx, s);
	}
	static void lload_0(Stack* s){ dload_x(0,s);}
	static void lload_1(Stack* s){ dload_x(1,s);}
	static void lload_2(Stack* s){ dload_x(2,s);}
	static void lload_3(Stack* s){ dload_x(3,s);}
	
	static void dload(Stack* s){
		int idx = s->getnextbyte();
		dload_x(idx, s);
	}	
	static void dload_0(Stack* s){ dload_x(0,s);}
	static void dload_1(Stack* s){ dload_x(1,s);}
	static void dload_2(Stack* s){ dload_x(2,s);}
	static void dload_3(Stack* s){ dload_x(3,s);}
	
	static void aload_x(int i, Stack* s){
		Pointer* p = s->fp()->getLocals()->get(i);
		s->pushRef(p);
		dout(debug_bytecodes, "aload_%i: %p, ",i,s->peek())
		TRACE_REC(
				  rec->push(rec->getStoreSlot(i));
				  )
	}
	//25
	static void aload(Stack* s){
		byte idx = s->getnextbyte();
		aload_x(idx,s);
	}
	static void aload_0(Stack* s){ aload_x(0,s);}
	static void aload_1(Stack* s){ aload_x(1,s);}
	static void aload_2(Stack* s){ aload_x(2,s);}
	static void aload_3(Stack* s){ aload_x(3,s);}
	
	static Pointer* aaload_f(StaticArray* a, int idx){
		checkNullPointer(a);
		if(idx<0 || idx >= a->array_length()){printf("idx:%i %i",idx,a->array_length());throwException("java/lang/ArrayIndexOutOfBoundsException");}	
		return a->get(idx);
	}
	
	
	static void iaload(Stack* s){
		int idx = (int)s->popPrim();
		StaticArray* a = (StaticArray*)s->popRef();
		s->pushPrim(aaload_f(a,idx));
		
		TRACE_REC(
		LIns* args[] = {CFIX(rec->pop(),rec->pop())};
		LIns* re = rec->lir->insCall(&aaload_f_ci,args);
		rec->push(re);		
		)
	}
	
	//50
	static void aaload(Stack* s){
		int idx = (int)s->popPrim();
		StaticArray* a = (StaticArray*)s->popRef();
		s->pushRef(aaload_f(a,idx));
		
		TRACE_REC(
		LIns* args[] = {CFIX(rec->pop(),rec->pop())};
		rec->push(rec->lir->insCall(&aaload_f_ci,args));
		)
	}
	
	static Pointer* baload_f(ByteArray* a, int idx){
		checkNullPointer(a);
		if(idx<0 || idx >= a->array_length()){printf("idx:%i %i",idx,a->array_length());throwException("java/lang/ArrayIndexOutOfBoundsException");}	
		return (Pointer*)a->get(idx);
	}

	//51
	static void baload(Stack* s){
		int idx = (int)s->popPrim();
		ByteArray* b = (ByteArray*)s->popRef();
		
		s->pushPrim(baload_f(b,idx));// (Integer*)i);
		TRACE_REC(
		LIns* args[] = {CFIX(rec->pop(),rec->pop())};
		rec->push(rec->lir->insCall(&baload_f_ci,args));
		)
	}
	
	//59-62
	inline static void istore_x(int i, Stack* s){
		s->fp()->getLocals()->setPrim(i,s->popPrim());
		dout(debug_bytecodes, "xstrore_%i:, ",i)
		TRACE_REC(
				  rec->putStoreSlot(i,rec->pop());
				  )
	}
	//54
	static void istore(Stack* s){
		int idx = s->getnextbyte();
		istore_x(idx, s);
	}
	
	static void istore_0(Stack* s){istore_x(0,s);}
	static void istore_1(Stack* s){istore_x(1,s);}
	static void istore_2(Stack* s){istore_x(2,s);}
	static void istore_3(Stack* s){istore_x(3,s);}
	
	static void fstore(Stack* s){
		int idx = s->getnextbyte();
		istore_x(idx, s);
	}
	static void fstore_0(Stack* s){istore_x(0,s);}
	static void fstore_1(Stack* s){istore_x(1,s);}
	static void fstore_2(Stack* s){istore_x(2,s);}
	static void fstore_3(Stack* s){istore_x(3,s);}
	
	inline static void dstore_x(int i, Stack* s){
		s->fp()->getLocals()->setPrim(i+1, s->popPrim());//low bits
		s->fp()->getLocals()->setPrim(i, s->popPrim());//high bits
		TRACE_REC(BLACKLIST_TRACE)
	}
	static void lstore(Stack* s){
		int idx = s->getnextbyte();
		dstore_x(idx, s);
	}
	static void lstore_0(Stack* s){dstore_x(0,s);}
	static void lstore_1(Stack* s){dstore_x(1,s);}
	static void lstore_2(Stack* s){dstore_x(2,s);}
	static void lstore_3(Stack* s){dstore_x(3,s);}
	
	static void dstore(Stack* s){
		int idx = s->getnextbyte();
		dstore_x(idx, s);
	}
	static void dstore_0(Stack* s){dstore_x(0,s);}
	static void dstore_1(Stack* s){dstore_x(1,s);}
	static void dstore_2(Stack* s){dstore_x(2,s);}
	static void dstore_3(Stack* s){dstore_x(3,s);}
	
	inline static void astore_x(int i, Stack* s){
		s->fp()->getLocals()->setRef(i,s->popRef());
		dout(debug_bytecodes, "astrore_%i:, ",i)
		TRACE_REC(
				  rec->putStoreSlot(i,rec->pop());
				  )
	}
	//75-78
	static void astore_0(Stack* s){astore_x(0,s);}
	static void astore_1(Stack* s){astore_x(1,s);}
	static void astore_2(Stack* s){astore_x(2,s);}
	static void astore_3(Stack* s){astore_x(3,s);}
	
	static void astore(Stack* s){
		byte idx = s->getnextbyte();
		astore_x(idx, s);
	}
	
	static void aastore_f(StaticArray* a, int idx, Pointer* value){
		//check value if it is assignment compatible with array if not ArrayStoreException
		checkNullPointer(a);
		if(idx < 0 || idx >= a->array_length()){throwException("java/lang/ArrayIndexOutOfBoundsException");}
		a->set(idx, value);
	}

	
	//79
	static void iastore(Stack* s){
		Pointer* value = s->popRef();
		int idx = (int)s->popPrim();
		StaticArray* a = (StaticArray*)s->popRef();
		aastore_f(a, idx, value);
		
		TRACE_REC(
		LIns* args[] = {CFIX(rec->pop(),rec->pop(),rec->pop())};
		rec->lir->insCall(&aastore_f_ci,args);
		)
		
	}
	//83
	static void aastore(Stack* s){
		Pointer* value = s->popRef();
		int idx = (int)s->popPrim();
		StaticArray* a = (StaticArray*)s->popRef();
		aastore_f(a, idx, value);
		TRACE_REC(
		LIns* args[] = {CFIX(rec->pop(),rec->pop(),rec->pop())};
		rec->lir->insCall(&aastore_f_ci,args);
		)
	}
	//84
	static void bastore(Stack* s){
		int value = (int)s->popPrim();
		int idx = (int)s->popPrim();
		ByteArray* b = (ByteArray*)s->popRef();
		
		if(b->getInternalType()->value() != IType_ByteArray){throwException("java/lang/ArrayStoreException");}
		checkNullPointer(b);
		if(idx < 0 || idx >= b->array_length()){throwException("java/lang/ArrayIndexOutOfBoundsException");}
		b->set(idx,value);
		TRACE_REC(BLACKLIST_TRACE)
	}
	//87
	static void pop(Stack* s){
		s->popPrim();
		TRACE_REC(rec->pop();)
	}
	static void pop2(Stack* s){
		s->popU8();
		TRACE_REC(rec->pop();)
		//this is bad, need to fix this some how, in nanojit I only work with refs so is this double pop or two word pop?
	}
	
	//89		-needs some attention
	static void dup(Stack* s){
		if(s->isTopRef())
			s->pushRef(s->peek());
		else
			s->pushPrim(s->peek());
		dout(debug_bytecodes,"dup:, ",0)
		TRACE_REC(
				  LIns* l = rec->pop();
				  rec->push(l);
				  rec->push(l);
				  )
	}
	//90
	static void dup_x1(Stack* s){ //this is also a problem becuase of doubles, soulution in the simulation push double refs twice.
		Pointer* a = s->popPrim();
		Pointer* b = s->popPrim();
		s->pushPrim(a);	s->pushPrim(b);	s->pushPrim(a);
		dout(debug_bytecodes,"dup_x1:, ",0)
		TRACE_REC(
				  LIns* la = rec->pop();
				  LIns* lb = rec->pop();
				  rec->push(la);
				  rec->push(lb);
				  rec->push(la);
				  )
	}
	//91
	static void dup_x2(Stack* s){
		Pointer* a = s->popPrim();
		Pointer* b = s->popPrim();
		Pointer* c = s->popPrim();
		s->pushPrim(a); s->pushPrim(c); s->pushPrim(b);	s->pushPrim(a);
		dout(debug_bytecodes,"dup_x2:, ",0)
		TRACE_REC(
				  LIns* la = rec->pop();
				  LIns* lb = rec->pop();
				  LIns* lc = rec->pop();
				  rec->push(la);
				  rec->push(lc);
				  rec->push(lb);
				  rec->push(la);
				  )	
	}
	//92
	static void dup2(Stack* s){
		Pointer* a = s->popPrim();
		Pointer* b = s->peek();
		s->pushPrim(a);	s->pushPrim(b);	s->pushPrim(a);
		dout(debug_bytecodes,"dup2:, ",0);
		TRACE_REC(
				  LIns* la = rec->pop();
				  LIns* lb = rec->pop();
				  rec->push(la);
				  rec->push(lb);
				  rec->push(la);
				  )	
	}
	
	//95					-need some attention
	static void swap(Stack* s){
		Pointer *a = s->popPrim(), *b = s->popPrim();
		s->pushPrim(a); s->pushPrim(b);
		dout(debug_bytecodes,"swap",0);
		TRACE_REC(
				  LIns* la = rec->pop();
				  LIns* lb = rec->pop();
				  rec->push(la);
				  rec->push(lb);
				  )	
	}
	
#define bin_x(x) int b = (int)s->popPrim();	int a = (int)s->popPrim(); int result = a x b; s->pushPrim((Integer*)result);
	
	//96
	static void iadd(Stack* s){	
		bin_x(+) 
		dout(debug_bytecodes, "iadd: %i + %i result: %i, ",a,b,(int)s->peek())
		TRACE_REC(
				  LIns* lb = rec->pop();
				  LIns* la = rec->pop();
				  LIns* lr = rec->lir->ins2(LIR_add,la,lb);
				  rec->push(lr);
				  )
	}
	//100
	static void isub(Stack* s){ 
		bin_x(-) dout(debug_bytecodes,"isub: %i - %i result: %i, ",a,b,(int)s->peek())
		TRACE_REC(
				  LIns* lb = rec->pop();
				  LIns* la = rec->pop();
				  LIns* lr = rec->lir->ins2(LIR_sub,la,lb);
				  rec->push(lr);
				  )
	}
	//104
	static void imul(Stack* s){ 
		bin_x(*) dout(debug_bytecodes,"imul: %i - %i result: %i, ",a,b,(int)s->peek())
		TRACE_REC(
				  LIns* lb = rec->pop();
				  LIns* la = rec->pop();
				  LIns* lr = rec->lir->ins2(LIR_mul,la,lb);
				  rec->push(lr);
				  )
	}
	//108
	static void idiv(Stack* s){
		int b = (int)s->popPrim(), a = (int)s->popPrim();
		if(b == 0) throwException("java/lang/ArithmeticException, division by zero...!!");
		int result = a/b;
		s->pushPrim((Integer*)result);
		dout(debug_bytecodes,"imul: %i/%i result: %i, ",a,b,(int)s->peek())
		TRACE_REC(
				  LIns* lb = rec->pop();
				  LIns* la = rec->pop();
				  LIns* lr = rec->lir->ins2(LIR_div,la,lb);//need to add guards
				  rec->push(lr);
				  )
	}
	//112
	static void irem(Stack* s){
		int b = (int)s->popPrim(), a = (int)s->popPrim();
		if(b == 0) throwException("java/lang/Exception, division by zero... stop!!");
		int result = a - (a/b)*b;
		s->pushPrim((Integer*)result);
		dout(debug_bytecodes,"irem: %i/%%i result: %i, ",a,b,(int)s->peek())	
		TRACE_REC(
				  LIns* lb = rec->pop();
				  LIns* la = rec->pop();
				  LIns* lm = rec->lir->ins2(LIR_div,la,lb);//TODO: fix this.
				  LIns* ln = rec->lir->ins2(LIR_mul,lm,lb);
				  LIns* lr = rec->lir->ins2(LIR_sub,la,ln);
				  rec->push(lr);
				  )
	}
	//116
	static void ineg(Stack* s){
		int a = (int)s->popPrim();
		int result = 0-a;
		s->pushPrim((Integer*)result);
		dout(debug_bytecodes,"ineg: 0-%i result: %i, ",a,(int)s->peek())
		TRACE_REC(
				  LIns* la = rec->pop();
				  LIns* lr = rec->lir->ins1(LIR_neg,la);
				  rec->push(lr);
				  )
	}
	//126
	static void iand(Stack* s){ 
		bin_x(&) dout(debug_bytecodes,"iand: %i&%i result: %i, ",a,b,(int)s->peek())
		TRACE_REC(
				  LIns* lb = rec->pop();
				  LIns* la = rec->pop();
				  LIns* lr = rec->lir->ins2(LIR_and,la,lb);
				  rec->push(lr);
				  )
	}
	//128
	static void ior(Stack* s){ 
		bin_x(|) dout(debug_bytecodes,"ior: %i|%i result: %i, ",a,b,(int)s->peek())
		TRACE_REC(
				  LIns* lb = rec->pop();
				  LIns* la = rec->pop();
				  LIns* lr = rec->lir->ins2(LIR_or,la,lb);
				  rec->push(lr);
				  )
	}
	//130
	static void ixor(Stack* s){ 
		bin_x(^) dout(debug_bytecodes,"ior: %i^%i result: %i, ",a,b,(int)s->peek())
		TRACE_REC(
				  LIns* lb = rec->pop();
				  LIns* la = rec->pop();
				  LIns* lr = rec->lir->ins2(LIR_xor,la,lb);
				  rec->push(lr);
				  )
	} 
	
	//132
	static void iinc(Stack* s){
		int idx = s->getnextbyte();
		signed char inc = s->getnextbyte();
		
		int prev = (int)s->fp()->getLocals()->get(idx);
		int result = prev + inc;
		s->fp()->getLocals()->setPrim(idx, (Integer*)result);
		dout(debug_bytecodes,"iinc:%i idx:%i by:%i result:%i, \n",prev,idx,inc,result)
		TRACE_REC(
				  LIns* incVal = rec->lir->ins2(LIR_add,rec->lir->insImm(inc), rec->getStoreSlot(idx));
				  rec->putStoreSlot(idx,incVal);
				  )
	}
	//133
	static void i2l(Stack* s){
		int i = (int)s->popPrim();
		s->pushLong(i);
		TRACE_REC(
				  LIns* l = rec->pop();
				  //manual sign extension
				  assert(false);
				  rec->push(l);
				  )
	}
	//134
	static void i2f(Stack* s){
		float f = (int)s->popPrim();
		s->pushPrim(*(Pointer**)&f);
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* r = rec->lir->ins1(LIR_i2f,l);
				  rec->push(r);
				  )
	}
	//135
	static void i2d(Stack* s){
		double d = (int)s->popPrim();
		s->pushDbl(d);
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* r = rec->lir->ins1(LIR_i2f,l);
				  rec->push(r);
				  )
	}
	//136
	static void l2i(Stack* s){
		int l = s->popLong();
		s->pushPrim((Pointer*)l);
		TRACE_REC(
				  LIns* i = rec->pop();
				  assert(false);
				  LIns* r = rec->lir->ins1(LIR_i2f,i);
				  rec->push(r);
				  )
	}
	//137
	static void l2f(Stack* s){
		float f = s->popLong();
		s->pushPrim(*(Pointer**)&f);
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* r = rec->lir->ins1(LIR_i2f,l);
				  rec->push(r);
				  )
	}
	//138
	static void l2d(Stack* s){
		double d = s->popLong();
		s->pushDbl(d);
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* r = rec->lir->ins1(LIR_i2f,l);
				  rec->push(r);
				  )
	}
	//139
	static void f2i(Stack* s){
		//it is 
		int i = (int)s->popPrim();
		s->pushPrim((Pointer*)i);
		
		TRACE_REC(BLACKLIST_TRACE)
	}
	//140
	static void f2l(Stack* s){
		u4 f = (u4)s->popPrim();
		u8 l = (u8) *((float*)&f);
		s->pushLong(l);
		TRACE_REC(BLACKLIST_TRACE)
	}
	//141
	static void f2d(Stack* s){
		//There must be a better way to do this.
		//Todo: fix!
		u4 f = (u4)s->popPrim();
		s->pushDbl(*((float*)&f));
		dout(debug_bytecodes,"f2d: %f\n")
		TRACE_REC(BLACKLIST_TRACE)
	}
	//142
	static void d2i(Stack* s){
		int d = (int)s->popDbl();
		s->pushPrim((Pointer*)d);
		dout(debug_bytecodes,"d2i: %i \n",d)	
		TRACE_REC(BLACKLIST_TRACE)
	}
	//143
	static void d2l(Stack* s){
		long long d = s->popDbl();
		s->pushLong(d);
		TRACE_REC(BLACKLIST_TRACE)
	}
	//144
	static void d2f(Stack* s){
		float f = s->popDbl();
		s->pushPrim(*(Pointer**)&f);
		TRACE_REC(BLACKLIST_TRACE)
	}
	//145
	static void i2b(Stack* s){
		char b = (int)s->popPrim();
		int i = b;
		s->pushPrim((Pointer*)i);
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* m = rec->lir->ins2(LIR_lsh,l,rec->lir->insImm(24));
				  LIns* r = rec->lir->ins2(LIR_rsh,m,rec->lir->insImm(24));
				  rec->push(r);
				  )
	}
	//146
	static void i2c(Stack* s){
		unsigned short c = (int)s->popPrim();
		int i = c;
		s->pushPrim((Pointer*)i);
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* m = rec->lir->ins2(LIR_lsh,l,rec->lir->insImm(16));
				  LIns* r = rec->lir->ins2(LIR_ush,m,rec->lir->insImm(16));
				  rec->push(r);
				  )
	}
	//147
	static void i2s(Stack* s){
		short c = (int)s->popPrim();
		int i = c;
		s->pushPrim((Pointer*)i);
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* m = rec->lir->ins2(LIR_lsh,l,rec->lir->insImm(16));
				  LIns* r = rec->lir->ins2(LIR_rsh,m,rec->lir->insImm(16));
				  rec->push(r);
				  )
	}
	
#define if_x(x) signed short index = s->getnextU4();\
int a = (int)s->popPrim();\
bool b = a x 0;\
s->fp()->flag_flow(s->fp()->getPC()-3, b);\
if(b){makeJump(index, s);}
	
	
	//153
	static void ifeq(Stack* s){
		if_x(==)
		dout(debug_bytecodes,"ifeq: %i==0 jump %i, ",a,index)
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* r = rec->lir->ins2(LIR_eq,l,rec->lir->insImm(0));
				  rec->guard(b,r,s->fp()->getPC(),index);
				  
				  )
	}
	//154
	static void ifne(Stack*s){
		if_x(!=)
		dout(debug_bytecodes,"ifne: %i!=0 jump %i, ",a,index)
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* r = rec->lir->ins2(LIR_eq,l,rec->lir->insImm(0));
				  rec->guard(!b,r, s->fp()->getPC(),-1*(index-6));
				  )
	}
	//155
	static void iflt(Stack* s){
		if_x(<)
		dout(debug_bytecodes,"iflt: %i<0 jump %i, ",a,index)
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* r = rec->lir->ins2(LIR_lt,l,rec->lir->insImm(0));
				  rec->guard(b,r, s->fp()->getPC(),index);
				  )
	}
	//156
	static void ifge(Stack* s){
		if_x(>=)
		dout(debug_bytecodes,"ifge: %i>=0 jump %i, ",a,index)
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* r = rec->lir->ins2(LIR_ge,l,rec->lir->insImm(0));
				  rec->guard(b,r, s->fp()->getPC(),index);
				  )
	}
	//157
	static void ifgt(Stack* s){
		if_x(>)
		dout(debug_bytecodes,"ifgt: %i>0 jump %i, ",a,index)
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* r = rec->lir->ins2(LIR_gt,l,rec->lir->insImm(0));
				  rec->guard(b,r, s->fp()->getPC(),index);
				  )
	}
	//158
	static void ifle(Stack* s){
		if_x(<=)
		dout(debug_bytecodes,"ifle: %i<=0 jump %i, ",a,index)
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* r = rec->lir->ins2(LIR_le,l,rec->lir->insImm(0));
				  rec->guard(b,r, s->fp()->getPC(),index);
				  )
	}
	
#define if_ix(x) signed short index = s->getnextU4(); \
int b = (int)s->popPrim(); int a = (int)s->popPrim(); \
bool c = a x b;\
s->fp()->flag_flow(s->fp()->getPC()-3, c);\
if(c){makeJump(index, s);}
	
	//159
	static void if_icmpeq(Stack* s){ 
		if_ix(==)	dout(debug_bytecodes,"if_icmpeq: %i==%i jump %i, ",a,b,index)
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* h = rec->pop();
				  LIns* r = rec->lir->ins2(LIR_eq,h,l);
				  rec->guard(c,r, s->fp()->getPC(),index);
				  )
	}
	//160
	static void if_icmpne(Stack* s){ 
		if_ix(!=)	dout(debug_bytecodes,"if_icmpne: %i!=%i jump %i, ",a,b,index)
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* h = rec->pop();
				  LIns* r = rec->lir->ins2(LIR_eq,h,l);
				  //small fix to get the resore pc right
				  rec->guard(!c,r, s->fp()->getPC(),-1*(index-6));
				  )
	}
	//161
	static void if_icmplt(Stack* s){
		if_ix(<) dout(debug_bytecodes,"if_icmplt: %i<%i jump %i, ",a,b,index)
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* h = rec->pop();
				  LIns* r = rec->lir->ins2(LIR_lt,h,l);
				  rec->guard(c,r, s->fp()->getPC(),index);
				  )
	}
	//162
	static void if_icmpge(Stack* s){ 
		
		if_ix(>=) 
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* h = rec->pop();
				  LIns* r = rec->lir->ins2(LIR_ge,h,l);
				  rec->guard(c,r, s->fp()->getPC(),index);//TODO: clean up...
				  )
	}
	//163
	static void if_icmpgt(Stack* s){ 
		if_ix(>) dout(debug_bytecodes,"if_icmpgt: %i>%i jump %i, ",a,b,index)
		TRACE_REC(
				  
				  LIns* l = rec->pop();
				  LIns* h = rec->pop();
				  
				  //LIns* args[] = {h};
				  //rec->lir->insCall(&printout_ci,args);
				  //LIns* args2[] = {l};
				  //rec->lir->insCall(&printout_ci,args2);
				  LIns* r = rec->lir->ins2(LIR_gt,h,l);
				  rec->guard(c,r, s->fp()->getPC(),index);
				  )
	}
	//164
	static void if_icmple(Stack* s){ 
		
		if_ix(<=) 
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* h = rec->pop();
				  LIns* r = rec->lir->ins2(LIR_le,h,l);
				  rec->guard(c,r, s->fp()->getPC(),index);
				  )
	}
	//165
	static void if_acmpeq(Stack* s){ 
		signed short index = s->getnextU4();
		Pointer* b = s->popRef(); 
		Pointer* a = s->popRef(); 
		bool c = a == b;
		s->fp()->flag_flow(s->fp()->getPC()-3, c);
		if(c){ 	
			makeJump(index, s);
		}
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* h = rec->pop();
				  LIns* r = rec->lir->ins2(LIR_eq,h,l);
				  rec->guard(c,r, s->fp()->getPC(),index);
				  )
	}
	//166
	static void if_acmpne(Stack* s){ 
		signed short index = s->getnextU4();
		Pointer* b = s->popRef(); 
		Pointer* a = s->popRef(); 
		bool c = a != b;
		s->fp()->flag_flow(s->fp()->getPC()-3, c);
		if(c){ 
			makeJump(index, s);
		}
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* h = rec->pop();
				  LIns* r = rec->lir->ins2(LIR_eq,h,l);
				  rec->guard(!c,r, s->fp()->getPC(),-1*(index-6));
				  )
	}
	//167
	static void _goto(Stack* s){
		signed short index = s->getnextU4();
		makeJump(index, s);
		dout(debug_bytecodes,"goto: %i \n",index)
		
	}
	//172
	static void ireturn(Stack* s){
		TRACE_REC(  //todo: fix copy coding..
		if(rec->level->levelpos == 0){ //is not in a inline method.
			Flags::recordTrace = false;
			rec->commitStore();
			JoosSideExit* exit = rec->createJoosSideExit(LoopExit);
			exit->pc = s->fp()->getPC()-1;
			rec->lir->insGuard(LIR_x,NULL, rec->createGuardRecord(exit));
			
			JMethod* m = s->fp()->getMethod();
			int loopstart = ((TraceTreeObject*)rec->fragment->vmprivate)->getStartPc();
			if((TraceRecorder*)m->backJump(loopstart) == rec ){ //everything ok
				
				if(rec->isBlackList()){
					m->blacklist(loopstart);
				}else{	
					rec->closeRecord();
				}
			}
		}else{ //ending a inline method
			rec->popLevel(true);
		}
		
		)
		Pointer* r = s->popPrim();
		s->popOffFrame();
		s->pushPrim(r);
		
		dout(debug_bytecodes,"ireturn: %p \n",r)
	}
	
	//176
	static void areturn(Stack* s){
		
		TRACE_REC(
		if(rec->level->levelpos == 0){ //is not in a inline method.
			Flags::recordTrace = false;
			rec->commitStore();
			JoosSideExit* exit = rec->createJoosSideExit(LoopExit);
			exit->pc = s->fp()->getPC()-1;
			rec->lir->insGuard(LIR_x,NULL, rec->createGuardRecord(exit));
			
			JMethod* m = s->fp()->getMethod();
			int loopstart = ((TraceTreeObject*)rec->fragment->vmprivate)->getStartPc();
			if((TraceRecorder*) m->backJump(loopstart) == rec ){ //everything ok
				
				if(rec->isBlackList()){
					m->blacklist(loopstart);
				}else{	
					rec->closeRecord();
				}
			}
		}else{ //ending a inline method
			rec->popLevel(true);
		}
		
		)
		Pointer* r = s->popRef();
		s->popOffFrame();
		s->pushRef(r);
		dout(debug_bytecodes,"areturn: %p \n",r);
		
	}
	//177
	static void _return(Stack* s){
		TRACE_REC(
		//return with in the body of a loop is like a nice exit from the loop. 
		//just write out the locals and set pc to current-1, let the bytecode do the popoff work.
		
		if(rec->level->levelpos == 0){ //is not in a inline method.
			
			rec->commitStore();
			JoosSideExit* exit = rec->createJoosSideExit(LoopExit);
			//we want to resume interpretation so this bytecode is the next to be interpreted.
			exit->pc = s->fp()->getPC()-1;
			//create the explicit exit.
			rec->lir->insGuard(LIR_x,NULL, rec->createGuardRecord(exit));
			dout(debug_trace, "create Loopguard on return pc: %i\n",exit->pc);
			rec->closeRecord();
			
		}else{ //ending a inline method
			
			rec->popLevel(false);
		}
		// }
		)
		//in thins case we need the info befor it is discarded
		s->popOffFrame();
	}
	
	inline static int getstatic_f(JStaticField* obj){
		return (int)obj->getValue();
	}
	inline static void putstatic_f(JStaticField* obj, Pointer* value){
		obj->setValue(value);
	}
	
	//178
	static void getstatic(Stack* s){
		unsigned short index = s->getnextU4();
		JStaticField* sfi = s->fp()->getType()->getStaticFieldWithIndex(index);
		//"IncompatibleClassChangeError"is handled in the getStaticField also permissions
		const char* ret = ((String*)sfi->getReturnType())->str();
		if(ret[0] == 'D'|| ret[0] == 'J'){
			
			s->pushPrim(sfi->getValue());
			s->pushPrim(sfi->getValue());
		}else if(ret[0] == 'L'|| ret[0] == '[')
			s->pushRef(sfi->getValue());
		else
			s->pushPrim(sfi->getValue());
		
		dout(debug_bytecodes, "getstatic: Name:%s Type:%s \n",sfi->getName()->str(),((String*)sfi->getReturnType())->str())
		TRACE_REC(
		LIns* args[] = {rec->insertPointer(sfi)};
		//LIns* args[] = {rec->lir->insImmPtr(sfi)};
		rec->push(rec->lir->insCall(&getstatic_f_ci,args));
		
		)
	}
	//179
	static void putstatic(Stack* s){
		unsigned short index = s->getnextU4();
		JStaticField* sfi = s->fp()->getType()->getStaticFieldWithIndex(index);
		//"IncompatibleClassChangeError"is handled in the getStaticField also permissions
		sfi->setValue(s->popRef());
		
		dout(debug_bytecodes, "putstatic: Name:%s Type:%s \n",sfi->getName()->str(),((String*)sfi->getReturnType())->str())
		TRACE_REC(
		LIns* args[] = {CFIX(rec->pop(), rec->insertPointer(sfi))};
		rec->lir->insCall(&putstatic_f_ci,args);
		)		 
	}
	
	//180
	static void getfield(Stack* s){
		unsigned short index = s->getnextU4();
		Instance* obj = (Instance*)s->popRef();
		
		checkNullPointer(obj);
		
		//check type
		s->pushRef(obj->getField(index));
		
		dout(debug_bytecodes, "getfield:, ",0)
		TRACE_REC(BLACKLIST_TRACE)
	}
	//181
	static void putfield(Stack* s){
		unsigned short index = s->getnextU4();
		Pointer* value = s->popRef();
		Instance* obj = (Instance*)s->popRef();
		obj->putField(index, value);
		TRACE_REC(BLACKLIST_TRACE)
	}
	
	static TaggedArray* getInvokeParams(bool _static, JMethod* method, Stack* s, int *parameterCount){
		
		//todo: move!!, and make nicer
		//resolve sig
		String* _type = (String*)method->getReturnType();
		std::string _str(_type->str());
		
		//I should move this to the initialzation.
		int max = _str.size();// method->getMaxLocals();
		
		std::string params[max];
		int parc = 0;
		int localsize = _static?0:1; //space for the object ref if not static.
		int len = _str.find(')');
		for(int x=0;x<len;x++){
			if(_str[x] == 'I'|| _str[x] == 'Z'|| _str[x] == 'S'||_str[x] == 'F'||_str[x] == 'C'||_str[x] == 'B'){
				params[parc++] = _str.substr(x, 1);
				localsize++;
			}else if(_str[x] == 'D' || _str[x] == 'J'){
				//params[parc++] = _str[x];//.substr(x, 1).c_str();
				params[parc++] = _str.substr(x, 1);
				localsize += 2;
			}else if(_str[x] == 'L'){
				int xs = _str.find(';',x);
				//params[parc++] = _str[x];//.substr(x, (xs-x)+1).c_str();
				params[parc++] = _str.substr(x, (xs-x)+1);
				x = xs;
				localsize++;
			}else if(_str[x] == '['){
				int xs = x;
				while(_str[++xs] == '[');//move past multi array
				if(_str[xs] == 'L'){
					xs = _str.find(';',xs);
					//params[parc++] = _str[x];//.substr(x, (xs-x)+1).c_str();
					params[parc++] = _str.substr(x, (xs-x)+1);
					x = xs;
				}else{
					//params[parc++] = _str[x];//.substr(x, (xs-x)+1).c_str();
					params[parc++] = _str.substr(x, (xs-x)+1);
					x = xs;
				}
				
				localsize++;
			}else if(_str[x] == '(' || _str[x] == ')'){
				;//skip
			}else{
				lassert(false, "error reading method type");
			}
			
		}
		
		int maxLocals = method->isNative()?localsize:method->getMaxLocals();
		
		TaggedArray* locals = TaggedArray::Initalize(maxLocals);
		locals->setArrayType((HeapObject*)Smi::fromInt(IType_Array));
		
		
		for(int x=parc-1; x>=0;x--){
			char c = params[x][0];
			if(c == 'I'|| c == 'Z'|| c == 'S'|| c == 'F'|| c == 'C'|| c == 'B'){
				locals->setPrim(--localsize, s->popPrim());
			}else if(c == 'L' || c == '['){
				locals->setRef(--localsize, s->popRef());
			}else if(c == 'D' || c == 'J'){
				locals->setPrim(--localsize, s->popPrim());
				locals->setPrim(--localsize, s->popPrim());
			}else{ 
				lassert(false,"error reading method paramenters");
			}
			
		}
		
		*parameterCount = parc;		
		return locals;
	}
	
	//182
	static void invokevirtual(Stack* s){
		unsigned short index = s->getnextU4();
		JMethod* method = s->fp()->getType()->lookupAndLinkMethod(index);
		
		if(method->isStatic()){throwException("java/lang/IncompatibleClassChangeError");}
		
		
		int parc;//number of parameters, from stack, excluding "this"
		TaggedArray* locals = getInvokeParams(false, method, s,&parc);
		
		Instance* objref = (Instance*)s->popRef();
		checkNullPointer(objref);
		
		if(locals->array_length() > 0)
			locals->setRef(0, objref);
		//if the resolved methods type matches the objref type were done.
		/*
		 No because if we have linked it then it is just the last one we resolved.
		 The soulution could be to have an array to store the methods with same name 
		 different signature.
		 When there are more than one. 
		 
		 Put pointers into Trace recorder so that they can be updated, 
		 So every time the method is called the pointers are passed with 
		 
		 that leves side-effects, that we leave for later.
		 */
		if(method->getContainingType() != objref->getType()){
			//ddout("booo not the right one %p %s, %p %s\n",method->getContainingType(),method->getContainingType()->getName()->str(),objref->getType(), objref->getType()->getName()->str());
			
			const char* cname = method->getName()->str();
			const char* creturntype = ((String*)method->getReturnType())->str();
			
			String* signature = String::Initialize(strlen(cname) + strlen(creturntype) + 1);
			signature->setStr(cname);
			signature->insertStr(creturntype, strlen(cname));
			
			
			JMethod* tmpMet = objref->getType()->lookupMethod(signature);
			if(tmpMet != NULL && !tmpMet->isStatic())
				method = tmpMet;
		}
		
		if(method->isNative()){
			TRACE_REC(rec;dout(debug_trace,"native method"))
			method->invokeNative(locals, s);
			
		}else{
			TRACE_REC(
					  dout(debug_trace,"\t%s",method->getName()->str())
					  rec->pushLevel(method, parc, false, s->fp()->getPC());
					  )
			
			s->pushOnFrame(method,locals);
			
		}
		dout(debug_interpreter,"	%s\n",method->getName()->str());
		dout(debug_bytecodes, "\n\ninvokevirtual: ClassName:%s Name:%s Type:%s \n",method->getContainingType()->getName()->str(), method->getName()->str());
	}
	
	//183
	static void invokespecial(Stack* s){
	/*
		Invocation rules not followed!! 
		TODO:fix..
	*/
		
		unsigned short index = s->getnextU4();
		JMethod* method =  s->fp()->getType()->lookupAndLinkMethod(index);
		//if(method->isNative() && method->isAbstact())
		
		int parc;//number of parameters, from stack, excluding "this"
		TaggedArray* locals = getInvokeParams(false, method, s,&parc);

		Instance* objref = (Instance*)s->popRef();
		checkNullPointer(objref);
		
		if(locals->array_length() > 0)
			locals->setRef(0, objref);
		
		TRACE_REC(BLACKLIST_TRACE)
		if(method->isNative()){
			//NativeMethods::callNativeMethod(method,locals,s);
			method->invokeNative(locals, s);
			//TRACE_REC(dout(debug_trace,"special native method"); BLACKLIST_TRACE)
		}else{
			//I need to make the recording befor the new frame is pushed on the stack.
			//TRACE_REC(
			//		  dout(debug_trace,"\t%s",method->getName()->str())
			//		  rec->pushLevel(method, parc, false, s->fp()->getPC());
			//		  )
			s->pushOnFrame(method,locals);
		}
		
		//s->activateFrame(method, true);
		dout(debug_interpreter,"	%s\n",method->getName()->str());
		dout(debug_bytecodes, "\n\ninvokespecial: ClassName:%s Name:%s \n",method->getContainingType()->getName()->str(), method->getName()->str());	
		
	}
	
	//184
	static void invokestatic(Stack* s){
		unsigned short index = s->getnextU4();
		JMethod* method  =  s->fp()->getType()->lookupAndLinkMethod(index);
		
		if(!method->isStatic()){
			printf("Not static method");exit(1);
		}
		
		
		int parc;//number of parameters, from stack, excluding "this"
		TaggedArray* locals = getInvokeParams(true, method, s,&parc);
		
		if(method->isNative()){
			//NativeMethods::callNativeMethod(method,locals,s);
			method->invokeNative(locals, s);
			//TRACE_REC(dout(debug_trace,"static native method"); BLACKLIST_TRACE)
		}else{
			//I need to make the recording befor the new frame is pushed on the stack.
			TRACE_REC(
					  dout(debug_trace,"\t%s",method->getName()->str())
					  rec->pushLevel(method, parc, true, s->fp()->getPC());
					  )
			
			s->pushOnFrame(method,locals);
			
		}
		dout(debug_interpreter,"	%s\n",method->getName()->str());
		dout(debug_bytecodes, "\n\ninvokestatic: ClassName:%s Name:%s\n",method->getContainingType()->getName()->str(),method->getName()->str());
	}
	
	//187
	static void _new(Stack* s){
		unsigned short index = s->getnextU4();
		JType* type =  s->fp()->getType()->lookupAndLinkType(index);
		
		Instance* obj = Instance::Initialize(type);
		s->pushRef(obj);
		dout(debug_bytecodes, "new: %s, ",type->getName()->str())
		TRACE_REC(BLACKLIST_TRACE)
	}
	
	//188
	static void newarray(Stack* s){
		int atype = s->getnextbyte();
		int count = (int)s->popPrim();
		if(count<0){throwException("java/lang/NegativeArraySizeException");}
		
		switch (atype) {
			case T_BOOLEAN:
				notImplemented(s);
				break;
			case T_FLOAT:
				notImplemented(s);
				break;
			case T_DOUBLE:
				notImplemented(s);
				break;
			case T_CHAR:
				notImplemented(s);
				break;
			case T_BYTE:
			{
				ByteArray* b = ByteArray::Initialize(count);
				b->clear();
			s->pushRef(b);
			}
				break;
			case T_SHORT:
				notImplemented(s);
				break;
			case T_INT:
			{	StaticArray* st= StaticArray::Initalize(count);
				st->setArrayType((HeapObject*) Smi::fromInt(IType_Array));
				s->pushRef(st);
			}
				break;
			case T_LONG:
				notImplemented(s);
				break;
			default:
				throwException("Unknown array type");exit(1);
				break;
		}
		TRACE_REC(BLACKLIST_TRACE)
	}
	
	//189
	static void anewarray(Stack* s){
		unsigned short index = s->getnextU4();
		int count = (int)s->popPrim();
		if(count<0)throwException("java/lang/NegativeArraySizeException");//throw NegativeArraySizeException
		
		JType* type =  s->fp()->getType()->lookupAndLinkType(index);
		
		StaticArray* a = StaticArray::Initalize(count);
		a->setArrayType(type);
		s->pushRef(a);
		TRACE_REC(BLACKLIST_TRACE)
	}
	
	
	static inline int arraylength_f(Array* obj){
		checkNullPointer(obj);
		return obj->array_length();
	}

	static void arraylength(Stack* s){
		Array* obj = (Array*)s->popRef();
		s->pushPrim((Integer*)arraylength_f(obj));
		TRACE_REC(
		//BLACKLIST_TRACE
		//lassert(false,"unimplemented record");
		LIns* args[] = {rec->pop()};
		rec->push(rec->lir->insCall(&arraylength_f_ci,args));
		)
	}
	
	//191
	static void athrow(Stack* s){
		Instance* obj = (Instance*)s->popRef();
		checkNullPointer(obj);
		throwException(obj->getType()->getName()->str());
		TRACE_REC(BLACKLIST_TRACE)
	}
	
	static void checkcast(Stack* s){
		s->getnextU4();
		//just skip checking for now.
		TRACE_REC(BLACKLIST_TRACE)
	}
	//193
	static void instanceof(Stack* s){
		unsigned short index = s->getnextU4();
		HeapObject* obj = (HeapObject*)s->popRef();
		checkNullPointer(obj);
		
		JType* type =  s->fp()->getType()->lookupAndLinkType(index);
		
		if(obj->getInternalType()->value() == IType_Instance){
			if(type != NULL || type == ((Instance*)obj)->getType())
				s->pushPrim((Integer*)1);
			else 
				s->pushPrim((Integer*)0);
		}else{
			lassert(false, "Un-implemented comparison")
		}
		TRACE_REC(BLACKLIST_TRACE)
	}
	//196
	static void wide(Stack* s){
		
		switch (s->getnextbyte()) {
			case 21: //iload
				iload_x(s->getnextU4(),s);
				break;
			case 22: //lload
				iload_x(s->getnextU4(),s);
				break;
			case 23: //fload
				dload_x(s->getnextU4(),s);
				break;
			case 24: //dload
				dload_x(s->getnextU4(),s);
				break;
			case 25: //aload
				aload_x(s->getnextU4(),s);
				break;
			case 54: //istore
				istore_x(s->getnextU4(),s);
				break;
			case 55: //lstore
				istore_x(s->getnextU4(),s);
				break;
			case 56: //fstore
				dstore_x(s->getnextU4(),s);
				break;
			case 57: //dstore
				dstore_x(s->getnextU4(),s);
				break;
			case 58: //astore
				astore_x(s->getnextU4(),s);
				break;
			default:
				notImplemented(s);
				break;
		}
	}
	
	static void multianewarray(Stack* s){
		notImplemented(s);
		
		
		unsigned short index = s->getnextU4();
		byte dimensions = s->getnextbyte();
		
		StaticArray* constpool = s->fp()->getType()->getConstantPool();
		Smi* class_info = (Smi*)constpool->get(index-1);
		String* class_name = ((String*)constpool->get(class_info->value() -1));
		
		class_name->isSmi();
		
		int* counts = new int[dimensions];
		int req_size =0;
		
		for(int i=0;i<dimensions;i++){
			counts[i] = (int)s->popPrim();
			req_size *= counts[i];
			if(counts[i]<0) 
				throwException("java/lang/NegativeArraySizeException");
		}
		
		int type_size = 0;//the size of the multiarray type
		req_size = req_size * type_size;
		req_size += (dimensions * StaticArray::kArrayOffset);//the size of a array header.
		
		
		delete counts;
	}
	
	//198
	static void ifnull(Stack* s){
		signed short index = s->getnextU4();
		Pointer* a = s->popRef(); 
		bool c =  a == NULL | (int)a==1;
		if(c){
			makeJump(index, s);
		}
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* h = rec->pop();
				  LIns* r = rec->lir->ins2(LIR_eq,h,l);
				  rec->guard(c,r, s->fp()->getPC(),index);
				  )
		
	}
	
	static void ifnonnull(Stack* s){
		signed short index = s->getnextU4();
		Pointer* a = s->popRef(); 
		bool c =  a == NULL | (int)a==1;
		if(!c){
			makeJump(index, s);
		}
		TRACE_REC(
				  LIns* l = rec->pop();
				  LIns* h = rec->pop();
				  LIns* r = rec->lir->ins2(LIR_eq,h,l);
				  rec->guard(c,r, s->fp()->getPC(),index);
				  )
	}
	
	static void terminate(Stack* s){
		//this is the only thread 
		//Flags::terminateExecution = true;
		Heap::threads[s->threadId()].terminate = true;
		TRACE_REC(BLACKLIST_TRACE)
	}
	
	static void notImplemented(Stack* s){
		//pickup the last bytecode and out it.
		byte b = s->fp()->getCode()->get(s->fp()->getPC()-1);
		printf("Bytecode not implemented: %s %i\n",LookupBytecode(b), b);
		exit(1);
	}
	
	
	
	
	

};

#endif
